﻿using Syncfusion.UI.Xaml.Grid;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using Common.Client.Lib.Extensions;

namespace Syncfusion.Lib.Controls
{
    /// <summary>
    /// SfGrid搜索面板
    /// </summary>
    [TemplatePart(Name = "PART_FindNext", Type = typeof(Button))]
    [TemplatePart(Name = "PART_FindPrevious", Type = typeof(Button))]
    [TemplatePart(Name = "PART_Close", Type = typeof(Button))]
    [TemplatePart(Name = "PART_ApplyFiltering", Type = typeof(CheckBox))]
    [TemplatePart(Name = "PART_ComboBox", Type = typeof(ComboBox))]
    [TemplatePart(Name = "PART_AdornerLayer", Type = typeof(AdornerDecorator))]
    [TemplatePart(Name = "PART_CaseSensitiveSearch", Type = typeof(CheckBox))]
    public class SfDataGridSearchPanel:Control, IDisposable
    {
        #region Fields
        internal Button? FindNextButton;
        internal Button? FindPreviousButton;
        internal Button? CloseButton;
        internal TextBox? SearchTextBox;
        internal CheckBox? ApplyFilterCheckBox;
        internal CheckBox? CaseSensitiveSearchCheckBox;
        internal AdornerDecorator? AdornerLayer;
        internal ComboBox? ComboBox;
        #endregion

        #region Properties

        /// <summary>
        /// 获取或设置相应搜索操作的DataGrid。
        /// </summary>
        public SfDataGrid? DataGrid
        {
            get => (SfDataGrid)GetValue(DataGridProperty);
            set => SetValue(DataGridProperty, value);
        }
        public static readonly DependencyProperty DataGridProperty =
            DependencyProperty.Register(nameof(DataGrid), typeof(SfDataGrid), typeof(SfDataGridSearchPanel), new PropertyMetadata(null));

        #endregion

        #region Ctor

        /// <summary>
        /// 静态默认构造函数
        /// </summary>
        static SfDataGridSearchPanel()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SfDataGridSearchPanel), new FrameworkPropertyMetadata(typeof(SfDataGridSearchPanel)));
        }

        public SfDataGridSearchPanel()
        {
        }

        public SfDataGridSearchPanel(SfDataGrid dataGrid)
        {
            DataGrid = dataGrid;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets the DetailsViewDefinition index of the given DataGrid. 
        /// </summary>
        /// <param name="dataGrid"></param>
        /// <param name="actualRowIdx"></param>
        /// <returns></returns>
        private int GetDetailsViewDefinitionIndex(SfDataGrid dataGrid, int actualRowIdx)
        {
            var counter0 = 0;
            for (int i = actualRowIdx; i > 0; i--)
            {
                if (!dataGrid.IsInDetailsViewIndex(i))
                {
                    break;
                }
                counter0++;
            }
            return counter0;
        }

        /// <summary>
        /// Method to open Search Control.
        /// </summary>
        /// <param name="visible"></param>
        internal void UpdateSearchControlVisibility(bool visible)
        {
            if (visible)
            {
                if (this.DataGrid?.SelectedDetailsViewGrid != null)
                {
                    var detailsViewIndex = this.DataGrid.GetGridDetailsViewRowIndex(this.DataGrid.SelectedDetailsViewGrid as DetailsViewDataGrid);
                    if (ComboBox != null)
                    {
                        ComboBox.SelectedIndex = this.GetDetailsViewDefinitionIndex(this.DataGrid, detailsViewIndex - 1) + 1;
                    }
                }
                else
                {
                    if (ComboBox != null)
                    {
                        ComboBox.SelectedIndex = 0;
                    }
                }
                this.Visibility = Visibility.Visible;
                if (SearchTextBox != null)
                {
                    this.SearchTextBox.Focus();
                    this.SearchTextBox.SelectionStart = SearchTextBox.Text.Length;
                }
            }
            else
            {
                this.Visibility = Visibility.Collapsed;
                this.SearchTextBox?.Clear();
                this.DataGrid?.SearchHelper?.ClearSearch();
                this.DataGrid?.Focus();
            }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            FindNextButton = this.GetTemplateChild("PART_FindNext") as Button;
            FindPreviousButton = this.GetTemplateChild("PART_FindPrevious") as Button;
            CloseButton = this.GetTemplateChild("PART_Close") as Button;
            ApplyFilterCheckBox = this.GetTemplateChild("PART_ApplyFiltering") as CheckBox;
            ComboBox = this.GetTemplateChild("PART_ComboBox") as ComboBox;
            SearchTextBox = this.GetTemplateChild("PART_TextBox") as TextBox;
            CaseSensitiveSearchCheckBox = this.GetTemplateChild("PART_CaseSensitiveSearch") as CheckBox;
            AdornerLayer = this.GetTemplateChild("PART_AdornerLayer") as AdornerDecorator;
            this.SearchTextBox?.Focus();
            this.WireEvents();
        }

        #endregion

        #region Events
        /// <summary>
        /// Method to wire the required events.
        /// </summary>
        private void WireEvents()
        {
            if (FindNextButton != null) FindNextButton.Click += OnFindNextButtonClick;
            if (FindPreviousButton != null) FindPreviousButton.Click += OnFindPreviousButtonClick;
            if (CloseButton != null) CloseButton.Click += OnCloseButtonClick;
            if (SearchTextBox != null) SearchTextBox.TextChanged += OnTextChanged;
            if (ApplyFilterCheckBox != null)
            {
                ApplyFilterCheckBox.Click += OnApplyFilterCheckBoxClick;
                if (ApplyFilterCheckBox != null)
                {
                    var grid = this.GetDataGrid("");
                    if (grid != null)
                    {
                        grid.SearchHelper.AllowFiltering = this.ApplyFilterCheckBox.IsChecked.GetValueOrDefault();
                    }
                }
            }

            if (CaseSensitiveSearchCheckBox != null)
                CaseSensitiveSearchCheckBox.Click += OnCaseSensitiveSearchCheckBoxClick;
            if (ComboBox != null)
            {
                ComboBox.SelectionChanged += OnComboBoxSelectionChanged;
            }

            if (AdornerLayer != null) AdornerLayer.KeyDown += OnAdornerLayerKeyDown;
        }

        /// <summary>
        /// Event handler to handle AdornerLayer key down.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnAdornerLayerKeyDown(object sender, KeyEventArgs e)
        {
            if ((e.Key == Key.F) && (e.KeyboardDevice.Modifiers & ModifierKeys.Control) != ModifierKeys.None)
            {
                this.UpdateSearchControlVisibility(true);

                var item = this.ComboBox?.SelectedItem;
                //if (item == null)
                //    return;
                var grid = this.GetDataGrid(item?.ToString());
                if (grid != null) 
                {
                    if (ApplyFilterCheckBox != null)
                    {
                        ApplyFilterCheckBox.IsChecked = grid.SearchHelper.AllowFiltering;
                    }
                    if(CaseSensitiveSearchCheckBox != null)
                    {
                        CaseSensitiveSearchCheckBox.IsChecked = grid.SearchHelper.AllowCaseSensitiveSearch;
                    }
                    if (SearchTextBox != null)
                    {
                        SearchTextBox.Text = grid.SearchHelper.SearchText;
                    }
                }
            } 
            else if (e.Key == Key.Escape)
            {
                var window = this.GetParent<Window>();
                if (window == null)
                {
                    this.UpdateSearchControlVisibility(false);
                }
                else
                {
                    window.Hide();
                }
            }
        }

        /// <summary>
        /// Event handler to handle CaseSensitive search check box click.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnCaseSensitiveSearchCheckBoxClick(object sender, RoutedEventArgs e)
        {
            var item = this.ComboBox?.SelectedItem;
            //if (item == null)
            //    return;
            var grid = this.GetDataGrid(item?.ToString());
            if (grid != null)
            {
                grid.SearchHelper.AllowCaseSensitiveSearch = (bool)this.CaseSensitiveSearchCheckBox?.IsChecked.GetValueOrDefault();
            }
        }


        /// <summary>
        /// Event handler to handle when text value is changed in SearchTextBox.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnTextChanged(object sender, TextChangedEventArgs e)
        {
            var item = this.ComboBox?.SelectedItem;
            //if (item == null)
            //    return;
            var grid = this.GetDataGrid(item?.ToString());     
            if(grid == null)
            {
                return;
            }
            try
            {
                grid.SearchHelper.Search(SearchTextBox?.Text);
                if (grid is { DataContext: not null, ItemsSource: not null })
                {
                    var searchRecords = grid.SearchHelper.GetSearchRecords();
                    if (SearchTextBox?.Text != string.Empty && searchRecords is not { Count: > 0 })
                    {
                        var findNextButton = this.FindNextButton;
                        if (findNextButton is { IsEnabled: true })
                        {
                            var nextButton = this.FindNextButton;
                            if (nextButton != null)
                                nextButton.IsEnabled = false;
                        }

                        var findPreviousButton = this.FindPreviousButton;
                        if (findPreviousButton is { IsEnabled: true })
                        {
                            var previousButton = this.FindPreviousButton;
                            if (previousButton != null)
                                previousButton.IsEnabled = false;
                        }
                    }
                    else
                    {
                        var findNextButton = this.FindNextButton;
                        if (findNextButton is { IsEnabled: false })
                        {
                            var nextButton = this.FindNextButton;
                            if (nextButton != null)
                                nextButton.IsEnabled = true;
                        }

                        var findPreviousButton = this.FindPreviousButton;
                        if (findPreviousButton is { IsEnabled: false })
                        {
                            var previousButton = this.FindPreviousButton;
                            if (previousButton != null)
                                previousButton.IsEnabled = true;
                        }
                    }
                }
            }
            catch (Exception)
            {
                // ignored
            }
        }


        /// <summary>
        ///  Event handler to handle when clicking on FindNext button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnFindNextButtonClick(object sender, RoutedEventArgs e)
        {
            var item = this.ComboBox?.SelectedItem;
            //if (item == null)
            //    return;
            var grid = this.GetDataGrid(item?.ToString());
            grid?.SearchHelper.FindNext(SearchTextBox?.Text);
        }


        /// <summary>
        /// Event handler to handle when clicking on FindPrevious button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnFindPreviousButtonClick(object sender, RoutedEventArgs e)
        {
            var item = this.ComboBox?.SelectedItem;
            //if (item == null)
            //    return;
            var grid = this.GetDataGrid(item?.ToString());
            grid?.SearchHelper.FindPrevious(SearchTextBox?.Text);
        }

        /// <summary>
        /// Event handler to handle when clicking on Close button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnCloseButtonClick(object sender, RoutedEventArgs e)
        {
            this.SearchTextBox?.Clear();
            var item = this.ComboBox?.SelectedItem;
            //if (item != null)
                this.GetDataGrid(item?.ToString())?.SearchHelper?.ClearSearch();
            //this.Visibility = Visibility.Collapsed;
            this.DataGrid?.Focus();
        }


        /// <summary>
        /// Event handler to handle ApplyFilter check box click.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnApplyFilterCheckBoxClick(object sender, RoutedEventArgs e)
        {
            var item = this.ComboBox?.SelectedItem;
            //if (item == null)
            //    return;
            var grid = this.GetDataGrid(item?.ToString());
            var applyFilterCheckBox = this.ApplyFilterCheckBox;
            if (applyFilterCheckBox != null && grid != null)
            {
                grid.SearchHelper.AllowFiltering = applyFilterCheckBox.IsChecked.GetValueOrDefault();
            }
        }


        /// <summary>
        /// Event handler to handle selection changes in DataGrid combo box.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnComboBoxSelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            var oldItem = e.RemovedItems[0];
            var newItem = e.AddedItems[0];
            if (oldItem == null || newItem == null)
                return;
            var oldGrid = this.GetDataGrid(oldItem.ToString());
            var newGrid = this.GetDataGrid(newItem.ToString());
            oldGrid?.SearchHelper.ClearSearch();
            var applyFilterCheckBox = this.ApplyFilterCheckBox;

            if (newGrid != null)
            {
                if (applyFilterCheckBox != null)
                        newGrid.SearchHelper.AllowFiltering = applyFilterCheckBox.IsChecked.GetValueOrDefault();
                var caseSensitiveSearchCheckBox = this.CaseSensitiveSearchCheckBox;
                if (caseSensitiveSearchCheckBox != null)
                    newGrid.SearchHelper.AllowCaseSensitiveSearch = caseSensitiveSearchCheckBox.IsChecked.GetValueOrDefault();
                newGrid.SearchHelper.Search(SearchTextBox?.Text);
            }
        }

        /// <summary>
        /// Method to return the DataGrid which Selected in the ComboBox.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private SfDataGrid? GetDataGrid(string? item)
        {
            switch (item)
            {
                case "Search first level Grid's":
                    return (this.DataGrid?.DetailsViewDefinition[0] as GridViewDefinition)?.DataGrid;
                case "Search second level Grid's":
                    return (this.DataGrid?.DetailsViewDefinition[1] as GridViewDefinition)?.DataGrid;
                default:
                    return this.DataGrid;
            }
        }
        #endregion Events


        /// <summary>
        /// Method to UnWire the wired events.
        /// </summary>
        private void UnWireEvents()
        {
            if (FindNextButton != null) FindNextButton.Click -= OnFindNextButtonClick;
            if (FindPreviousButton != null) FindPreviousButton.Click -= OnFindPreviousButtonClick;
            if (CloseButton != null) CloseButton.Click -= OnCloseButtonClick;
            if (SearchTextBox != null) SearchTextBox.TextChanged -= OnTextChanged;
            if (ApplyFilterCheckBox != null) ApplyFilterCheckBox.Click -= OnApplyFilterCheckBoxClick;
            if (ComboBox != null)
            {
                ComboBox.SelectionChanged -= OnComboBoxSelectionChanged;
            }
        }

        public void Dispose()
        {
            this.UnWireEvents();
            this.DataGrid = null;
        }
    }
}
